//////////////////////////////////////////////////////////////////////////
//
// This file is a part of UKROP project.
// Copyright (c) Vladimir Gumenuk
//
// PROJECT:         Xort Custom Debug Engine
// FILE:            Document.cpp : Implementation of CDocument
// AUTHOR:          Vladimir Gumenuk
// DATE:            Dec-2012 -- Jan-2013
// MODIFICATIONS:
//
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "xort.h"
#include "Document.h"
#include "dllmain.h"

// CDocument
CDocument::CDocument()
{
    ATLTRACE( "CDocument::CDocument()\n" );
    m_dwCurrentLine     = 0;
    m_dwCurrentColumn   = 0;
}

CDocument::~CDocument()
{
    ATLTRACE( "CDocument::~CDocument()\n" );
}

HRESULT CDocument::FinalConstruct()
{
    return S_OK;
}

void CDocument::FinalRelease()
{
}

STDMETHODIMP CDocument::Initialize( LPCSTR lpszFileName )
{
    m_bsFileName = CComBSTR( lpszFileName );
    return S_OK;
}

STDMETHODIMP CDocument::SetPosition( TEXT_POSITION *pPos )
{
    if( !pPos )
        return E_POINTER;
    m_dwCurrentLine   = pPos->dwLine;
    m_dwCurrentColumn = pPos->dwColumn;
    //ATLTRACE( "CDocument::SetPosition() -> %u\n", m_dwCurrentLine );
    return S_OK;
}

STDMETHODIMP CDocument::GetPosition( TEXT_POSITION *pPos )
{
    if( !pPos )
        return E_POINTER;
    pPos->dwLine   = m_dwCurrentLine;
    pPos->dwColumn = m_dwCurrentColumn;
    return S_OK;
}

STDMETHODIMP CDocument::GetName( BSTR* pbstrName )
{
    if( !pbstrName )
        return E_POINTER;
    *pbstrName = getFileName();
    return S_OK;
}

STDMETHODIMP CDocument::GetName( GETNAME_TYPE gnType, __RPC__deref_out_opt BSTR *pbstrName )
{
    HRESULT hr = S_OK;
    switch( gnType )
    {
    case GN_NAME: // friendly name
        *pbstrName = getFileName();
        break;

    case GN_FILENAME:
        *pbstrName = SysAllocString( m_bsFileName );
        break;

    case GN_BASENAME:
        *pbstrName = getFileName();
        break;

    case GN_MONIKERNAME:
    case GN_URL:
    case GN_TITLE:
    case GN_STARTPAGEURL:
    default:
        hr = S_FALSE;
        break;

    }
    return hr;
}

STDMETHODIMP CDocument::GetDocumentClassId( __RPC__out CLSID *pclsid )
{
    *pclsid = __uuidof(Document);
    return S_OK;
}

BSTR CDocument::getFileName() // simple returns the name of the file with extension without path
{
    WCHAR szDrive[_MAX_DRIVE+1];
    WCHAR szDir[_MAX_DIR+1];
    WCHAR szFName[_MAX_FNAME+1];
    WCHAR szExt[_MAX_EXT+1];

    _wsplitpath( m_bsFileName, szDrive, szDir, szFName, szExt );

    wcscat( szFName, szExt );
    return SysAllocString( szFName );
}

STDMETHODIMP CDocument::GetDocument( __RPC__deref_out_opt IDebugDocument2 **ppDocument)
{
    return this->QueryInterface( IID_IDebugDocument2, (void**)ppDocument );
}

STDMETHODIMP CDocument::EnumCodeContexts(  __RPC__deref_out_opt IEnumDebugCodeContexts2 **ppEnumCodeCxts)
{
    ATLTRACE( "CDocument::EnumCodeContexts()\n" );
    return E_NOTIMPL;
}

STDMETHODIMP CDocument::GetLanguageInfo( __RPC__deref_opt_inout_opt BSTR *pbstrLanguage, __RPC__inout_opt GUID *pguidLanguage )
{
    if( pbstrLanguage )
        *pbstrLanguage = CComBSTR( XORT_LANG_NAME );
    if( pguidLanguage )
        *pguidLanguage = IID_IXortLanguage;
    return S_OK;
}

//////////////////////////////////////////////////////////////////////////
// A statement range is the range of the lines that contributed the code to which this document context refers.
STDMETHODIMP CDocument::GetStatementRange( __RPC__inout_opt TEXT_POSITION *pBegPosition, __RPC__inout_opt TEXT_POSITION *pEndPosition)
{
    if( pBegPosition )
    {
        pBegPosition->dwLine   = m_dwCurrentLine;
        pBegPosition->dwColumn = m_dwCurrentColumn;
    }

    if( pEndPosition )
    {
        pEndPosition->dwLine   = m_dwCurrentLine;
        pEndPosition->dwColumn = m_dwCurrentColumn;
    }
    return S_OK;
}

// A source range is the entire range of source code, from the current statement back to just after 
// the previous statement that contributed code. The source range is typically used for mixing source statements, 
// including comments, with code in the disassembly window.
STDMETHODIMP CDocument::GetSourceRange( __RPC__inout_opt TEXT_POSITION *pBegPosition, __RPC__inout_opt TEXT_POSITION *pEndPosition)
{
    if( pBegPosition )
    {
        pBegPosition->dwLine = m_dwCurrentLine;
        pBegPosition->dwColumn = m_dwCurrentColumn;
    }

    if( pEndPosition )
    {
        pEndPosition->dwLine = m_dwCurrentLine;
        pEndPosition->dwColumn = m_dwCurrentColumn;
    }

    return S_OK;
}

STDMETHODIMP CDocument::Compare( DOCCONTEXT_COMPARE compare, IDebugDocumentContext2 **rgpDocContextSet, DWORD dwDocContextSetLen, DWORD *pdwDocContext )
{
    ATLTRACE( "CDocument::Compare()\n" );
    return E_NOTIMPL;
}

// Moves the document context by a given number of statements or lines.
STDMETHODIMP CDocument::Seek( int nCount, IDebugDocumentContext2 **ppDocContext )
{
    //ATLTRACE( "CDocument::Seek()\n" );
    if( !ppDocContext )
        return E_INVALIDARG;

    /*if( nCount == -1 ) // move to next statement or line
    {
        DWORD dwIP;
        _AtlModule.getXProgramNoAddRef()->GetCurrentIP( &dwIP );
        SetNextStatement( dwIP );
    }*/

    return this->QueryInterface( IID_IDebugDocumentContext2, (void**)ppDocContext );
}

////////////////////////////////////////////////////////////////////////////// 
// IDebugMemoryContext2 methods 
STDMETHODIMP CDocument::GetInfo( CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO* pInfo ) 
{
    return E_NOTIMPL;
}

STDMETHODIMP CDocument::Add( UINT64 dwCount, IDebugMemoryContext2** ppMemCxt ) 
{
    return E_NOTIMPL;
}

STDMETHODIMP CDocument::Subtract( UINT64 dwCount, IDebugMemoryContext2** ppMemCxt ) 
{
    return E_NOTIMPL;
}

STDMETHODIMP CDocument::Compare( CONTEXT_COMPARE compare, IDebugMemoryContext2** rgpMemoryContextSet, DWORD dwMemoryContextSetLen, DWORD* pdwMemoryContext ) 
{
    return E_NOTIMPL;
} 

////////////////////////////////////////////////////////////////////////////// 
// IDebugCodeContext2 methods 
STDMETHODIMP CDocument::GetDocumentContext( IDebugDocumentContext2 **ppSrcCxt ) 
{ 
    return this->QueryInterface( IID_IDebugDocumentContext2, (void**)ppSrcCxt ); 
} 
